/*
 * Copyright 2011 Jin Kwon <jinahya at gmail.com>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package com.googlecode.flac4j.format.metadata;


import com.googlecode.flac4j.format.FormatHelper;

import com.googlecode.jinahya.io.BitInput;
import com.googlecode.jinahya.io.BitOutput;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

import java.util.Arrays;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.XmlType;


/**
 *
 * @author Jin Kwon <jinahya at gmail.com>
 */
@XmlType(propOrder = {"pictureType", "mediaType", "description", "width",
                      "height", "colorDepth", "colorCount", "data"})
public class Picture extends AbstractData {


    /** GENERATED. */
    private static final long serialVersionUID = 4027529856958050356L;


    public static final String MEDIA_TYPE_LINK = "-->";


    public static final int COLOR_COUNT_NON_INDEXED = 0;


    /**
     * Creates a new instance.
     */
    public Picture() {
        super(BlockType.PICTURE);
    }


    @Override
    public int getLengthInBytes() {

        int length = 0;

        length += 4;

        try {
            final byte[] mediaTypeBytes = mediaType.getBytes("US-ASCII");
            length += 4 + mediaTypeBytes.length;
        } catch (UnsupportedEncodingException uee) {
            throw new RuntimeException(uee.getMessage());
        }

        try {
            final byte[] descriptionBytes = description.getBytes("UTF-8");
            length += 4 + descriptionBytes.length;
        } catch (UnsupportedEncodingException uee) {
            throw new RuntimeException(uee.getMessage());
        }

        length += 4 + 4 + 4 + 4;

        length += 4 + data.length;

        return length;
    }


    @Override
    public void read(final BitInput input) throws IOException {

        setPictureType(PictureType.valueOf(input.readInt(32)));

        final byte[] mediaTypeBytes = new byte[input.readInt(32)];
        FormatHelper.readBytes(input, mediaTypeBytes);
        setMediaType(new String(mediaTypeBytes, "US-ASCII"));

        final byte[] descriptionBytes = new byte[input.readInt(32)];
        FormatHelper.readBytes(input, descriptionBytes);
        setDescription(new String(descriptionBytes, "UTF-8"));

        setWidth(input.readInt(32));
        setHeight(input.readInt(32));
        setColorDepth(input.readInt(32));
        setColorCount(input.readInt(32));

        data = new byte[input.readInt(32)];
        FormatHelper.readBytes(input, data);
    }


    @Override
    public void write(final BitOutput output) throws IOException {

        output.writeInt(32, getPictureType().getValue());

        final byte[] mediaTypeBytes = mediaType.getBytes("US-ASCII");
        output.writeInt(32, mediaTypeBytes.length);
        FormatHelper.writeBytes(output, mediaTypeBytes);

        final byte[] descriptionBytes = description.getBytes("UTF-8");
        output.writeInt(32, descriptionBytes.length);
        FormatHelper.writeBytes(output, descriptionBytes);

        output.writeInt(32, getWidth());
        output.writeInt(32, getHeight());
        output.writeInt(32, getColorDepth());
        output.writeInt(32, getColorCount());

        output.writeInt(32, data.length);
        FormatHelper.writeBytes(output, data);
    }


    // ------------------------------------------------------------- pictureType
    /**
     * Returns pictureType.
     *
     * @return pictureType
     */
    public PictureType getPictureType() {
        return pictureType;
    }


    /**
     * Sets pictureType.
     *
     * @param pictureType pictureType
     */
    public void setPictureType(final PictureType pictureType) {

        if (pictureType == null) {
            throw new NullPointerException("null pictureType");
        }

        this.pictureType = pictureType;
    }


    // --------------------------------------------------------------- mediaType
    /**
     * Returns mediaType.
     *
     * @return mediaType.
     */
    public String getMediaType() {
        return mediaType;
    }


    /**
     * Sets mediaType.
     *
     * @param mediaType mediaType.
     */
    public void setMediaType(final String mediaType) {

        if (mediaType == null) {
            throw new NullPointerException("null mediaType");
        }

        this.mediaType = mediaType;
    }


    // ------------------------------------------------------------- description
    /**
     * Returns description.
     *
     * @return description.
     */
    public String getDescription() {
        return description;
    }


    /**
     * Sets description.
     *
     * @param description description.
     */
    public void setDescription(final String description) {
        this.description = description;
    }


    // ------------------------------------------------------------------- width
    /**
     * Returns width.
     *
     * @return width.
     */
    public int getWidth() {
        return width;
    }


    /**
     * Sets width.
     *
     * @param width width
     */
    public void setWidth(final int width) {

        if (width <= 0) {
            throw new IllegalArgumentException("width(" + width + ") < 0");
        }

        this.width = width;
    }


    // ------------------------------------------------------------------ height
    /**
     * Returns height.
     *
     * @return height
     */
    public int getHeight() {
        return height;
    }


    /**
     * Sets height.
     *
     * @param height height.
     */
    public void setHeight(final int height) {

        if (height <= 0) {
            throw new IllegalArgumentException("height(" + height + ") <= 0");
        }

        this.height = height;
    }


    // -------------------------------------------------------------- colorDepth
    /**
     * Returns colorDepth.
     *
     * @return colorDepth.
     */
    public int getColorDepth() {
        return colorDepth;
    }


    /**
     * Sets colorDepth.
     *
     * @param colorDepth colorDepth.
     */
    public void setColorDepth(final int colorDepth) {

        if (colorDepth <= 0) {
            throw new IllegalArgumentException(
                "colorDepth(" + colorDepth + ") <= 0");
        }

        this.colorDepth = colorDepth;
    }


    // -------------------------------------------------------------- colorCount
    /**
     * Returns colorCount.
     *
     * @return colorCount
     */
    public int getColorCount() {
        return colorCount;
    }


    /**
     * Sets colorCount.
     *
     * @param colorCount colorCount.
     */
    public void setColorCount(final int colorCount) {

        if (colorCount < 0) {
            throw new IllegalArgumentException(
                "colorCount(" + colorCount + ") < 0");
        }

        this.colorCount = colorCount;
    }


    // -------------------------------------------------------------------- data
    /**
     * Returns data.
     *
     * @return data
     */
    public byte[] getData() {
        return Arrays.copyOf(data, data.length);
    }


    /**
     * Sets data.
     *
     * @param data data
     */
    public void setData(final byte[] data) {

        if (data == null) {
            throw new NullPointerException("null data");
        }

        this.data = Arrays.copyOf(data, data.length);
    }


    @XmlElement(required = true)
    private PictureType pictureType;


    @XmlElement(required = true)
    private String mediaType;


    @XmlElement(required = true)
    private String description;


    @XmlElement(required = true)
    private int width;


    @XmlElement(required = true)
    private int height;


    @XmlElement(required = true)
    private int colorDepth;


    @XmlElement(required = true)
    private int colorCount;


    @XmlElement(required = true)
    @XmlSchemaType(name = "base64Binary")
    private byte[] data;


}

